﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Soft.Service
{

    /// <summary>
    /// 功能集合类
    /// </summary>
    public sealed class ProcessCollection : ErrorResponse, IDebug
    {

        public ProcessCollection()
        {
            this.JobInstanceList = new List<JobInstance>();
            this.Services = new List<JobInstance>();
            this.TimedTasks = new TimedScheduling();
            this.ProcessItems = new List<ProcessItem>();
            this.TimedTasks.Error += this.OnError;
        }


        /// <summary>
        /// 发出输出信息的事件通知
        /// </summary>
        public event InformationEventHandle Information;


        /// <summary>
        /// job运行的实例
        /// </summary>
        public List<JobInstance> JobInstanceList { get; private set; }

 
        /// <summary>
        /// 服务的实例
        /// </summary>
        public List<JobInstance> Services { get; private set; }

     
        /// <summary>
        /// 任务调度器 需要被定时调度的任务集合
        /// </summary>
        public TimedScheduling TimedTasks { get; private set; }


        /// <summary>
        /// 处理单元的集合【方法(FunctionCode)的集合】
        /// </summary>
        public List<ProcessItem> ProcessItems { get; private set; }


        /// <summary>
        /// 是否是Debug模式
        /// </summary>
        public bool Debug { get; set; }


        /// <summary>
        /// 调用方法触发的事件
        /// </summary>
        public ExecuteMethodCallInstructionEventHandle ExecuteMethodCallInstruction;


        /// <summary>
        /// 加载程序集的服务
        /// </summary>
        /// <param name="dllConfig"></param>
        /// <returns></returns>
        public Assembly AppendDll(DllConfig dllConfig)
        {
            if (dllConfig == null)
            {
                throw new ArgumentNullException("dllConfig");
            }
            //所有的ClassConfig
            List<ClassConfig> list = new List<ClassConfig>(dllConfig);
            string text = FactoryAdvisorPlatformGlobalSet.ApplicationPath + dllConfig.File;
            if (File.Exists(text))
            {
                Assembly assembly = null;
                try
                {
                    assembly = Assembly.LoadFrom(text);
                    this.OnInformation(InformationType.Prompt, "Loaded dll file: " + text, this);
                }
                catch (Exception e)
                {
                    this.OnError(e);
                    return null;
                }
                Type[] types = assembly.GetTypes();
                for (int k = 0; k < types.Length; k++)
                {
                    Type type = types[k];
                    try
                    {
                        //如果基类是BaseJob
                        if (type.TypeAs(typeof(BaseJob)))
                        {
                            ///获取是否有有自定义的Disabeled属性
                            DisabledAttribute customAttribute = type.GetCustomAttribute<DisabledAttribute>(false);
                            if (customAttribute != null)
                            {
                                this.OnError(new Information(InformationType.Prompt, string.Concat(new string[]
                                {
                                    "类 ",
                                    type.AssemblyQualifiedName,
                                    " 被赋予了 ",
                                    typeof(DisabledAttribute).FullName,
                                    " 附加属性，系统忽略这个类。"
                                })));
                            }
                            else
                            {
                                //如果DisabledAttribute 为空,则获取是否含有JobClassInfoAttribute特性
                                JobClassInfoAttribute customAttribute2 = type.GetCustomAttribute<JobClassInfoAttribute>(false);
                                if (customAttribute2 != null)
                                {
                                    //作为service 需要继承IServerControl接口
                                    if (customAttribute2.Mode == JobServiceMode.Service && !type.TypeAs(typeof(IServerControl)))
                                    {
                                        this.OnError(string.Concat(new string[]
                                        {
                                            "被指定为服务类型的业务类 ",
                                            type.AssemblyQualifiedName,
                                            " 没有继承 ",
                                            typeof(IServerControl).FullName,
                                            " 接口。"
                                        }));
                                    }//作为定时任务 需要继承BaseTimedTask接口
                                    else if (customAttribute2.Mode == JobServiceMode.TimedTask && !type.TypeAs(typeof(BaseTimedTask)))
                                    {
                                        this.OnError(string.Concat(new string[]
                                        {
                                            "被指定为定时业务的类 ",
                                            type.AssemblyQualifiedName,
                                            " 没有继承 ",
                                            typeof(BaseTimedTask).FullName,
                                            " 基类。"
                                        }));
                                    }
                                    else
                                    {
                                        //如果是作为service ，继承了IServiceControl
                                        if (customAttribute2.Mode == JobServiceMode.Service)
                                        {
                                            //使用jobInstance封装
                                            JobInstance jobInstance = new JobInstance(type, customAttribute2.Mode, this.ExecuteMethodCallInstruction, null);
                                            this.JobInstanceList.Add(jobInstance);
                                            ClassConfig classConfig = list.Find((ClassConfig e) => e.Class == type.FullName);
                                            if (classConfig != null)
                                            {
                                                jobInstance.StartType = classConfig.StartType;
                                            }
                                            this.Services.Add(jobInstance);
                                        }
                                        else
                                        {
                                            //如果作为定时任务 继承了BaseTimedTask接口
                                            if (customAttribute2.Mode == JobServiceMode.TimedTask)
                                            {
                                                ClassConfig classConfig2 = list.Find((ClassConfig e) => e.Class == type.FullName);
                                                //如果是定时任务且没有ClassConfig的xml配置  
                                                if (classConfig2 == null)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
                                                {
                                                    //添加方法处理项
                                                    AppendProcessItem(type, customAttribute2, list);
                                                    continue;
                                                }
                                                //获取ClassConfig下的TimedTaskConfig
                                                using (IEnumerator<TimedTaskConfig> enumerator = classConfig2.TimedTasks.GetEnumerator())
                                                {
                                                    ///遍历调度任务集合
                                                    while (enumerator.MoveNext())
                                                    {
                                                        TimedTaskConfig timedTaskConfig = enumerator.Current;
                                                        if (!this.JobInstanceList.Exists((JobInstance i) => i.InstanceType == type && i.Name == timedTaskConfig.Name))
                                                        {
                                                            JobInstance jobInstance2 = new JobInstance(type, customAttribute2.Mode, this.ExecuteMethodCallInstruction, timedTaskConfig.Name);
                                                            this.JobInstanceList.Add(jobInstance2);
                                                            SchedulingTask schedulingTask = new SchedulingTask(jobInstance2, timedTaskConfig.Parameter, this.Debug);
                                                            ///任务输出信息
                                                            schedulingTask.Information += delegate (Information e)
                                                            {
                                                                InformationEventHandle information = this.Information;
                                                                if (information == null)
                                                                {
                                                                    return;
                                                                }
                                                                information(e);
                                                            };
                                                            schedulingTask.TaskInfo.BeginTime = timedTaskConfig.BeginTime;
                                                            schedulingTask.TaskInfo.Cycle = timedTaskConfig.Cycle;
                                                            schedulingTask.TaskInfo.Enabled = timedTaskConfig.Enabled;
                                                            schedulingTask.TaskInfo.RepeatMode = timedTaskConfig.RepeatMode;
                                                            schedulingTask.TaskInfo.StartTime = timedTaskConfig.StartTime;
                                                            schedulingTask.TaskInfo.Delayed = timedTaskConfig.Delayed;
                                                            //将job的定时任务 添加到调度中
                                                            this.TimedTasks.AddTask(schedulingTask);
                                                        }
                                                    }
                                                }
                                            }


                                            //添加到JobInstanceList集合中
                                            JobInstance item = new JobInstance(type, customAttribute2.Mode, this.ExecuteMethodCallInstruction, null);
                                            this.JobInstanceList.Add(item);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception e2)
                    {
                        this.OnError(e2);
                        return null;
                    }
                }
                return assembly;
            }
            this.OnError("The DLL file '" + dllConfig.File + "' does not exist.");
            return null;
        }


        private void AppendProcessItem(Type type, JobClassInfoAttribute customAttribute2, List<ClassConfig> list)
        {
            this.OnInformation(InformationType.Prompt, string.Concat(new string[]
            {
                "\tLoaded class: \"",
                type.FullName,
                "\", run mode: \"",
                customAttribute2.Mode.ToString(),
                "(",
                ToolsClass.GetEnumerateDescription(customAttribute2.Mode),
                ")\""
            }), this);

            Predicate<ClassConfig> classConfigFilter = null;
            Predicate<JobInstance> jobInstanceFilter = null;


            //获取类型中定义的方法
            foreach (MethodInfo methodInfo in type.GetMethods())
            {
                //获取方法中定义的JobMethodInfoAttribute特性
                JobMethodInfoAttribute customAttribute3 = methodInfo.GetCustomAttribute<JobMethodInfoAttribute>(false);
                //有JobMethodInfo特性且可以执行(action=true)
                if (customAttribute3 != null && customAttribute3.Action)
                {
                    //检查方法的返回值类型 是否是Resul类型
                    if (methodInfo.ReturnType.TypeAs(typeof(Result)))
                    {
                        //如果类属性 是定时任务
                        if (customAttribute2.Mode == JobServiceMode.TimedTask)
                        {
                            List<ClassConfig> list2 = list;
                            Predicate<ClassConfig> match;
                            if ((match = classConfigFilter) == null)
                            {
                                match = (classConfigFilter = ((ClassConfig e) => e.Class == type.FullName));
                            }
                            ClassConfig classConfig3 = list2.Find(match);
                            if (classConfig3 == null)
                            {
                                continue;
                            }
                            using (IEnumerator<TimedTaskConfig> enumerator2 = classConfig3.TimedTasks.GetEnumerator())
                            {
                                while (enumerator2.MoveNext())
                                {
                                    TimedTaskConfig timedTaskConfig = enumerator2.Current;
                                    JobInstance instance = this.JobInstanceList.Find((JobInstance i) => i.InstanceType == type && i.Name == timedTaskConfig.Name);
                                    AppendProcessItem(new FunctionSign(timedTaskConfig.Name, customAttribute3.FunctionCode), instance, methodInfo, customAttribute3, customAttribute2);
                                }
                                continue;
                            }
                        }


                        //如果不是定时任务  则找出类型上的所有的打FunctionCode的方法  添加到ProcessItem中
                        List<JobInstance> jobInstanceList = this.JobInstanceList;
                        Predicate<JobInstance> match2;
                        if ((match2 = jobInstanceFilter) == null)
                        {
                            match2 = (jobInstanceFilter = ((JobInstance i) => i.InstanceType == type));
                        }
                        JobInstance instance2 = jobInstanceList.Find(match2);
                        AppendProcessItem(new FunctionSign(customAttribute3.FunctionCode), instance2, methodInfo, customAttribute3, customAttribute2);
                    }
                    else
                    {
                        this.OnError(string.Concat(new string[]
                        {
                            type.FullName,
                            ".",
                            methodInfo.Name,
                            "的返回值没有继承接口",
                            typeof(IResult).FullName,
                            "。"
                        }));
                    }
                }
            }
        }


        /// <summary>
        /// 发送消息的方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="text"></param>
        /// <param name="sender"></param>
        private void OnInformation(InformationType type, string text, object sender)
        {
            InformationEventHandle information = this.Information;
            if (information == null)
            {
                return;
            }
            information(new Information(type, text, sender));
        }


        /// <summary>
        /// 执行方法调用的指令
        /// </summary>
        /// <param name="callInstruction"></param>
        /// <returns></returns>
        private CarrierJson OnExecuteMethodCallInstruction(CallMethodInstruction callInstruction)
        {
            ExecuteMethodCallInstructionEventHandle executeMethodCallInstruction = this.ExecuteMethodCallInstruction;
            if (executeMethodCallInstruction == null)
            {
                return null;
            }
            return executeMethodCallInstruction(callInstruction);
        }


        /// <summary>
        /// 添加功能项
        /// </summary>
        /// <param name="functionSign">方法签名</param>
        /// <param name="instance">Job实例</param>
        /// <param name="methodInfo">方法信息</param>
        /// <param name="jobMethodAttribute">方法特性</param>
        /// <param name="jobClassAttribute">Class特性</param>
        private void AppendProcessItem(FunctionSign functionSign, JobInstance instance, MethodInfo methodInfo, JobMethodInfoAttribute jobMethodAttribute, JobClassInfoAttribute jobClassAttribute)
        {
            if (!this.ProcessItems.Exists((ProcessItem e) => e.FunctionSign.FullCode == functionSign.FullCode))
            {
                ParameterInfo[] parameters = methodInfo.GetParameters();
                MethodCallInfo method = new MethodCallInfo(methodInfo.Name, jobMethodAttribute.Explain, methodInfo.ReturnType, parameters.Length != 0, parameters);
                ProcessItem processItem = new ProcessItem(functionSign, jobClassAttribute.Mode, method, instance.InstanceType, instance);
                processItem.Error += this.OnError;
                this.ProcessItems.Add(processItem);
                if (this.Debug)
                {
                    this.OnInformation(InformationType.Prompt, "\t\tRegistered method: " + jobMethodAttribute.FunctionCode + " --> " + methodInfo.Name, this);
                    return;
                }
            }
            else
            {
                ProcessItem processItem2 = this.ProcessItems.Find((ProcessItem e) => e.FunctionSign.Code == functionSign.Code);
                this.OnError(string.Concat(new string[]
                {
                    "方法'",
                    instance.InstanceType.FullName,
                    ".",
                    methodInfo.Name,
                    "'的功能号'",
                    jobMethodAttribute.FunctionCode,
                    "'与方法'",
                    processItem2.JobClassType.FullName,
                    ".",
                    processItem2.Method.MethodName,
                    "'功能号重复"
                }));
            }
        }

      
    }
}
